package com.tianxiao.faas.biz.service.corner;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.tianxiao.faas.api.param.corner.*;
import com.tianxiao.faas.biz.domain.entity.SearchEntity;
import com.tianxiao.faas.biz.domain.entity.ShopDetailEntity;
import com.tianxiao.faas.common.constants.CommonConstants;
import com.tianxiao.faas.common.exception.biz.BizException;
import com.tianxiao.faas.common.result.Result;
import com.tianxiao.faas.common.util.*;
import com.tianxiao.faas.mapper.dao.GoodsModelMapper;
import com.tianxiao.faas.mapper.dao.OrderHistoryModelMapper;
import com.tianxiao.faas.mapper.dao.ShopModelMapper;
import com.tianxiao.faas.mapper.dao.TagsModelMapper;
import com.tianxiao.faas.mapper.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ShopService {
    @Resource
    private ShopModelMapper shopModelMapper;
    @Resource
    private TagsModelMapper tagsModelMapper;

    @Resource
    private GoodsModelMapper goodsModelMapper;

    @Resource
    private OrderHistoryModelMapper orderHistoryModelMapper;

    @Value("${ai.host}")
    private String aiHost;

    @Value("${ai.searchPath}")
    private String searchPath;

    final static Logger logger = LoggerFactory.getLogger(ShopService.class);


    public List<TagEntity> getTags(boolean all) {
        List<TagsModel> tagsModels = null;
        if (all) {
            tagsModels = tagsModelMapper.getAllTags();
        } else {
            tagsModels = tagsModelMapper.getTags();
        }
        return buildTagEntity(tagsModels);
    }

    public ShopModel getByUserId(Long userId) {
        ShopModel shopModel = shopModelMapper.selectByUserId(userId);
        return shopModel;
    }

    public ShopModel getById(Long shopId) {
        ShopModel shopModel = shopModelMapper.selectByPrimaryKey(shopId);
        return shopModel;
    }

    public Result<List<ShopResult>> page(ShopPageParam param) {
        String tagId = param.getTagName();
        List<ShopModel> list = Lists.newArrayList();
        Integer count = 0;
        Integer page = param.getPage();
        if (StringUtils.isNotEmpty(tagId)) {
            List<Long> shopIds = tagsModelMapper.page(tagId, PageUtils.getOffset(page, param.getPageSize()), param.getPageSize());
            if (!CollectionUtils.isEmpty(shopIds)) {
                ShopModelExample example = new ShopModelExample();
                example.createCriteria().andIdIn(shopIds).andDeletedEqualTo(0);
                example.setOrderByClause("updated desc");
                list = shopModelMapper.selectByExample(example);
                count = tagsModelMapper.count(tagId);
            }
        } else {
            String key = param.getKey();
            key = LikeQueryUtils.getKey(key);
            list = shopModelMapper.list(key, param.getCategoryId(), PageUtils.getOffset(page, param.getPageSize()), param.getPageSize());
            count = count(param);
        }

        List<Long> shopIds = list.stream().map(ShopModel::getId).collect(Collectors.toList());
        Map<Long, List<TagsModel>> map = getLongListMap(shopIds);
        List<ShopResult> shopResults = getShopResults(param.getLatitude(), param.getLongitude(), list, map);
        return Result.builder().success(true).totalCount(count).pageSize(param.getPageSize()).pageNo(page).totalPage().data(shopResults);
    }


    public Integer count(BasePageParam param) {
        String key = param.getKey();
        key = LikeQueryUtils.getKey(key);
        return shopModelMapper.count(key, param.getCategoryId());
    }

    public List<ProductResult> getProductsByShopId(Long shopId) {
        List<GoodsModel> goodsModels = goodsModelMapper.queryByShopId(shopId);
        return buildProductResults(goodsModels);
    }

    public List<ProductResult> buildProductResults(List<GoodsModel> page) {
        List<ProductResult> results = new ArrayList<>();
        for (GoodsModel good : page) {
            ProductResult productResult = new ProductResult();
            productResult.setId(good.getId());
            productResult.setImg(good.getImages());
            productResult.setIndex(good.getSort());
            productResult.setName(good.getName());
            productResult.setInfo(good.getInfo());
            productResult.setShopId(good.getShopId());
            Long price = good.getPrice();
            price = price == null ? 0 : price;
            productResult.setPrice(new BigDecimal(price / 100).doubleValue());
            productResult.setRecommendTxt(good.getRecommend());
            results.add(productResult);
        }
        return results;
    }

    public Map<Long, List<TagsModel>> getLongListMap(List<Long> shopIds) {
        if (CollectionUtils.isEmpty(shopIds)) {
            return new HashMap<>(1);
        }
        TagsModelExample example = new TagsModelExample();
        example.createCriteria().andShopIdIn(shopIds).andDeletedEqualTo(0);
        List<TagsModel> tagsModels = tagsModelMapper.selectByExample(example);
        Map<Long, List<TagsModel>> map = new HashMap<>();
        for (TagsModel tag : tagsModels) {
            Long shopId = tag.getShopId();
            List<TagsModel> tagsModels1 = map.get(shopId);
            if (tagsModels1 == null) {
                map.put(shopId, Lists.newArrayList(tag));
            } else {
                tagsModels1.add(tag);
            }
        }
        return map;
    }

    public List<ShopResult> listByUserIds(List<Long> list) {
        ShopModelExample example = new ShopModelExample();
        example.createCriteria().andUserIdIn(list).andDeletedEqualTo(0);
        List<ShopModel> shopModels = shopModelMapper.selectByExampleWithBLOBs(example);
        List<ShopResult> data = Lists.newArrayList();
        if (CollectionUtils.isEmpty(shopModels)) {
            return data;
        } else {
            for (ShopModel shop : shopModels) {
                data.add(getShopResult(null, null, shop, null));
            }
        }
        return data;
    }

    public List<ShopModel> listByIds(List<Long> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        ShopModelExample example = new ShopModelExample();
        example.createCriteria().andIdIn(list).andDeletedEqualTo(0);
        List<ShopModel> shopModels = shopModelMapper.selectByExampleWithBLOBs(example);

        return shopModels;
    }

    public List<ShopResult> list(List<Long> list, Double latitude, Double longitude) {
        ShopModelExample example = new ShopModelExample();
        example.createCriteria().andIdIn(list).andDeletedEqualTo(0);
        List<ShopModel> shopModels = shopModelMapper.selectByExampleWithBLOBs(example);
        List<ShopResult> data = getShopResults(latitude, longitude, shopModels, null);
        return data;
    }

    private List<ShopResult> getShopResults(Double latitude, Double longitude, List<ShopModel> shopModels, Map<Long, List<TagsModel>> tags) {
        List<ShopResult> data = Lists.newArrayList();
        if (CollectionUtils.isEmpty(shopModels)) {
            return Lists.newArrayList();
        } else {
            for (ShopModel shop : shopModels) {
                data.add(getShopResult(latitude, longitude, shop, tags));
            }
        }
        return data;
    }

    public ShopResult getShopResult(Double latitude, Double longitude, ShopModel shop, Map<Long, List<TagsModel>> tags) {
        ShopResult shopResult = new ShopResult();
        shopResult.initAddress(shop.getAddress());
        Long id = shop.getId();
        shopResult.setId(id);
        String images = shop.getImages();
        if (images != null) {
            List<String> strings = JSONArray.parseArray(images, String.class);
            if (strings != null && strings.size() > 0) {
                shopResult.setImg(strings.get(0));
            }
            shopResult.setImgs(strings);
        }
        List<TagEntity> tagEntities = buildTagEntity(tags, id);
        shopResult.setTags(tagEntities);
        shopResult.setUserId(shop.getUserId());
        shopResult.setName(shop.getName());
        shopResult.setLogo(shop.getLogo());
        shopResult.setCreateTime(DateUtils.format(shop.getCreated()));
        shopResult.setEditTime(DateUtils.format(shop.getUpdated()));
        shopResult.setOpenTime(shop.getOpenTime());
        shopResult.setCategoryId(shop.getCategoryId());
        shopResult.setRecommendTxt(shop.getRecommend());
        shopResult.setPoi(shop.getPoi());
        shopResult.setReport(shop.getShopReport());
        shopResult.setAveragePrice(shop.getPerCapitaConsumption() == null ? 0 : shop.getPerCapitaConsumption().doubleValue());
        shopResult.setDistance(GeoUtils.getDistanceStr(latitude, longitude, shop.getGreatness(), shop.getLongitude()));
        return shopResult;
    }

    public List<TagEntity> buildTagEntity(Map<Long, List<TagsModel>> tags, Long id) {
        List<TagEntity> tagEntities = new ArrayList<>();
        if (tags != null) {
            List<TagsModel> tagsModels = tags.get(id);
            return buildTagEntity(tagsModels);
        }
        return tagEntities;
    }

    private List<TagEntity> buildTagEntity(List<TagsModel> tagsModels) {
        List<TagEntity> tagEntities = new ArrayList<>();
        if (tagsModels != null) {
            for (TagsModel tag : tagsModels) {
                tagEntities.add(new TagEntity(tag.getId(), tag.getName()));
            }
        }
        return tagEntities;
    }

    public void buildShopConfig(ShopInfoParam param, ShopModel shop) {
        String config = shop.getConfig();
        ShopDetailEntity shopDetailEntity = null;
        if (config != null) {
            shopDetailEntity = JSONObject.parseObject(config, ShopDetailEntity.class);
        } else {
            shopDetailEntity = new ShopDetailEntity();
        }
        boolean needSave = false;
        if (StringUtils.isNotEmpty(param.getStory())) {
            shopDetailEntity.setStory(param.getStory());
            needSave = true;
        }
        String mobile = param.getMobile();
        if (StringUtils.isNotEmpty(mobile)) {
            shopDetailEntity.setTel(mobile);
            needSave = true;
        }
        if (StringUtils.isNotEmpty(param.getDesc())) {
            shopDetailEntity.setDesc(param.getDesc());
            needSave = true;
        }
        if (needSave) {
            shop.setConfig(JSON.toJSONString(shopDetailEntity));
        }
    }

    public void save(ShopModel shop) {
        long created = System.currentTimeMillis();
        shop.setUpdated(created);
        if (shop.getId() == null) {
            shop.setCreated(created);
            shop.setDeleted(0);
            shopModelMapper.insertSelective(shop);
        } else {
            shopModelMapper.updateByPrimaryKeySelective(shop);
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    public void saveShopInfo(ShopInfoAdminParam param) {
        Long id = param.getId();
        ShopModel shopFromDB = getById(id);

        ShopModel shop = new ShopModel();
        if (shopFromDB != null) {
            shop.setId(shopFromDB.getId());
        }
        Long userId = param.getUserId();
        if (userId == null) {
            shop.setAddress(param.address());
            shop.setGreatness(param.getLatitude());
            shop.setLogo(param.getLogo() == null ? "" : param.getLogo());
            if (!CollectionUtils.isEmpty(param.getImgs())) {
                shop.setImages(JSON.toJSONString(param.getImgs()));
            }
            shop.setLongitude(param.getLongitude());
            shop.setName(param.getName());
            shop.setOpenTime(param.getTime());
            if (param.getCategoryId() != null) {
                shop.setCategoryId(param.getCategoryId());
            }
            if (StringUtils.isNotEmpty(param.getPoi())) {
                shop.setPoi(param.getPoi());
            }
            if (StringUtils.isNotEmpty(param.getReport())) {
                shop.setShopReport(param.getReport());
            }
            if (StringUtils.isNotEmpty(param.getRecommendTxt())) {
                shop.setRecommend(param.getRecommendTxt());
            }
            if (param.getAveragePrice() != 0) {
                shop.setPerCapitaConsumption(new BigDecimal(param.getAveragePrice()));
            }
            buildShopConfig(param, shop);
        } else {
            shop.setUserId(userId);
        }
        save(shop);
        if (!CollectionUtils.isEmpty(param.getProducts())) {
            //saveProducts(param.getProducts(), shop);
        }
        id = id == null ? shop.getId() : id;
        List<TagEntity> tags = param.getTags();
        if (!CollectionUtils.isEmpty(tags)) {
            List<TagsModel> tagsModels = getTagsModelsByShopId(id);
            tagsModels = tagsModels == null ? new ArrayList<>() : tagsModels;
            List<String> tagsNames = tagsModels.stream().map(TagsModel::getName).collect(Collectors.toList());
            Map<String, TagsModel> tagsModelMap = tagsModels.stream().collect(Collectors.toMap(TagsModel::getName, s -> s, (s1, s2) -> s1));
            List<String> handleNames = Lists.newArrayList();
            for (TagEntity tagEntity : tags) {
                String name = tagEntity.getName();
                handleNames.add(name);
                TagsModel tagsModel = tagsModelMap.get(name);
                if (tagsModel == null) {
                    tagEntity.setId(null);
                    createTag(tagEntity, shop);
                } else {
                    if (tagsModel.getDeleted() == 1) {
                        tagEntity.setId(tagsModel.getId());
                        tagEntity.setDelete(false);
                        createTag(tagEntity, shop);
                    }
                }
            }
            tagsNames.removeAll(handleNames);
            if (!CollectionUtils.isEmpty(tagsNames)) {
                for (String tagName : tagsNames) {
                    TagsModel model = tagsModelMap.get(tagName);
                    TagEntity tagsModel = new TagEntity();
                    tagsModel.setId(model.getId());
                    tagsModel.setDelete(true);
                    createTag(tagsModel, shop);
                }
            }
        }
    }

    public List<TagsModel> getTagsModelsByShopId(Long id) {
        if (id == null) {
            return Lists.newArrayList();
        }
        TagsModelExample example1 = new TagsModelExample();
        example1.createCriteria().andShopIdEqualTo(id);
        return tagsModelMapper.selectByExample(example1);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void saveProducts(List<ProductResult> params, ShopModel shop) {
        if (CollectionUtils.isEmpty(params)) {
            return;
        }
        List<GoodsModel> goodsModels = Lists.newArrayList();
        if (shop != null) {
            goodsModels = goodsModelMapper.queryByShopId(shop.getId());
            if (CollectionUtils.isEmpty(goodsModels)) {
                goodsModels = Lists.newArrayList();
            }
        }
        List<Long> ids = goodsModels.stream().map(GoodsModel::getId).collect(Collectors.toList());
        for (ProductResult param : params) {
            GoodsModel goodsModel = new GoodsModel();
            long currentTimeMillis = System.currentTimeMillis();
            goodsModel.setUpdated(currentTimeMillis);
            goodsModel.setId(param.getId());
            goodsModel.setImages(param.getImg());
            goodsModel.setName(param.getName());
            if (shop != null) {
                goodsModel.setShopId(shop.getId());
            }
            goodsModel.setSort(param.getIndex());
            double price = param.getPrice();
            if (price != 0) {
                goodsModel.setPrice(new BigDecimal(price * 100).longValue());
            }
            if (StringUtils.isNotEmpty(param.getInfo())) {
                goodsModel.setInfo(param.getInfo());
            }
            if (StringUtils.isNotEmpty(param.getRecommendTxt())) {
                goodsModel.setRecommend(param.getRecommendTxt());
            }
            if (goodsModel.getId() != null) {
                ids.remove(param.getId());
                if (param.getDelete()) {
                    goodsModel.setDeleted(1);
                }
                goodsModelMapper.updateByPrimaryKeySelective(goodsModel);
            } else {
                goodsModel.setDeleted(0);
                goodsModel.setCreated(currentTimeMillis);
                goodsModelMapper.insertSelective(goodsModel);
            }
        }
    }

    public void createTag(TagEntity param, ShopModel byUserId) {
        if (param == null) {
            return;
        }
        TagsModel tagsModel = new TagsModel();
        long currentTimeMillis = System.currentTimeMillis();
        tagsModel.setUpdated(currentTimeMillis);
        tagsModel.setName(param.getName());
        tagsModel.setShopId(byUserId.getId());
        tagsModel.setId(param.getId());
        if (tagsModel.getId() == null) {
            tagsModel.setDeleted(0);
            tagsModel.setCreated(currentTimeMillis);
            tagsModelMapper.insertSelective(tagsModel);
        } else {
            if (param.isDelete()) {
                tagsModel.setDeleted(1);
            } else {
                tagsModel.setDeleted(0);
            }
            TagsModelExample example = new TagsModelExample();
            example.createCriteria().andIdEqualTo(tagsModel.getId());
            tagsModelMapper.updateByExampleSelective(tagsModel, example);
        }
    }

    public ShopInfoResult getShopInfoParam(ShopModel shop, Double latitude, Double longitude) {
        Long userId = shop.getUserId();
        Long id = shop.getId();
        ShopInfoResult shopInfoParam = new ShopInfoResult();
        shopInfoParam.initAddress(shop.getAddress());
        shopInfoParam.setId(id);
        shopInfoParam.setImgs(JSON.parseArray(shop.getImages(), String.class));
        shopInfoParam.setLatitude(shop.getGreatness());
        shopInfoParam.setLogo(shop.getLogo() == null ? StringUtils.EMPTY : shop.getLogo());
        shopInfoParam.setLongitude(shop.getLongitude());
        shopInfoParam.setName(shop.getName());
        shopInfoParam.setTime(shop.getOpenTime());
        shopInfoParam.setUserId(userId);
        shopInfoParam.setCategoryId(shop.getCategoryId());
        shopInfoParam.setRecommendTxt(shop.getRecommend());
        shopInfoParam.setPoi(shop.getPoi());
        shopInfoParam.setReport(shop.getShopReport());
        shopInfoParam.setAveragePrice(shop.getPerCapitaConsumption() == null ? 0 : shop.getPerCapitaConsumption().doubleValue());
        shopInfoParam.setDistance(GeoUtils.getDistanceStr(latitude, longitude, shop.getGreatness(), shop.getLongitude()));
        String config = shop.getConfig();
        if (StringUtils.isNotEmpty(config)) {
            ShopDetailEntity shopDetailEntity = JSONObject.parseObject(config, ShopDetailEntity.class);
            shopInfoParam.setDesc(shopDetailEntity.getDesc());
            shopInfoParam.setStory(shopDetailEntity.getStory());
            shopInfoParam.setMobile(shopDetailEntity.getTel());
        }
        return shopInfoParam;
    }

    public List<SearchShopResult> search(SearchShopPageParam param, String top, String kind, Long userId) {
        String name = param.getName();
        HashMap<String, String> params = new HashMap<>();
        params.put("query", name);
        params.put("top", top);
        params.put("kind", kind);
        logger.info("search params:{}", JSON.toJSONString(params));
        String result = HttpClientUtil.doPostJson(aiHost + searchPath, JSON.toJSONString(params));
        logger.info("shop search result:{}", result);
        List<SearchShopResult> searchData = getSearchData(result);
        if (CollectionUtils.isEmpty(searchData)) {
            throw new BizException("搜索数据为空");
        }
        Integer type = CommonConstants.SEARCH_HISTORY_SHOP_TYPE;
        if (kind.equals(CommonConstants.SCENE_KIND)) {
            type = CommonConstants.SEARCH_HISTORY_SCENE_TYPE;
        }
       // searchHistoryService.save(userId, name, type);
        return searchData;
    }

    private SearchShopResult getSearchShopResult(ShopModel shopModel, SearchEntity.Shop shop) {
        SearchShopResult searchShopResult = new SearchShopResult();
        searchShopResult.setId(shop.getId());
        searchShopResult.setImages(shopModel.getImages());
        searchShopResult.setName(shop.getShopName());
        searchShopResult.setRecommend(shopModel.getRecommend());
        searchShopResult.setPoiAddress(shopModel.getPoi());
        searchShopResult.setPerCapitaConsumption(shopModel.getPerCapitaConsumption());
        searchShopResult.setLatitude(shopModel.getLongitude());
        searchShopResult.setGreatness(shopModel.getGreatness());
        return searchShopResult;
    }

    public void deleteShop(Long id) {
        long updated = System.currentTimeMillis();
        ShopModel shopModel = new ShopModel();
        shopModel.setId(id);
        shopModel.setUpdated(updated);
        shopModel.setDeleted(1);
        shopModelMapper.updateByPrimaryKeySelective(shopModel);
    }

    private List<SearchShopResult> getSearchData(String result) {
        SearchEntity searchEntity = JSONObject.parseObject(result, SearchEntity.class);
        List<SearchEntity.Shop> shops = searchEntity.getShops();
        if (CollectionUtils.isEmpty(shops)) {
            return Collections.emptyList();
        }
        List<Long> ids = shops.stream().map(SearchEntity.Shop::getId).collect(Collectors.toList());
        List<ShopModel> shopModels = shopModelMapper.queryByIds(ids);
        Map<Long, ShopModel> shopModelMap = shopModels.stream().collect(Collectors.toMap(ShopModel::getId, s -> s));

        List<SearchShopResult> searchShopResults = new ArrayList<>();
        for (SearchEntity.Shop shop : shops) {
            ShopModel shopModel = shopModelMap.get(shop.getId());
            if (shopModel == null) {
                continue;
            }
            SearchShopResult searchShopResult = getSearchShopResult(shopModel, shop);
            searchShopResults.add(searchShopResult);
        }
        return searchShopResults;
    }

    public ShopDetailsResult shopDetails(Long shopId, Long userId) {
        ShopModel shopModel = shopModelMapper.selectByPrimaryKey(shopId);
        if (shopModel == null) {
            throw new BizException("搜索店铺不能为空");
        }
        ShopDetailsResult shopDetailsResult = new ShopDetailsResult();
        shopDetailsResult.setId(shopId);
        shopDetailsResult.setImages(shopModel.getImages());
        shopDetailsResult.setName(shopModel.getName());
        shopDetailsResult.setShopReport(shopModel.getShopReport());
        shopDetailsResult.setOpenTime(shopModel.getOpenTime());
        shopDetailsResult.setAddress(shopModel.getAddress());
        shopDetailsResult.setPerCapitaConsumption(shopModel.getPerCapitaConsumption());
        OrderHistoryModel orderHistoryModel = orderHistoryModelMapper.selectByShopId(userId, shopId, CommonConstants.HISTORY_REPORT);
        OrderHistoryModel orderHistoryModel1 = new OrderHistoryModel();
        long l = System.currentTimeMillis();
        orderHistoryModel1.setCreated(l);
        orderHistoryModel1.setUpdated(l);
        if (orderHistoryModel == null) {
            UUID uuid = UUID.randomUUID();
            String shareId = uuid.toString().replaceAll("-", "");
            orderHistoryModel1.setShopId(shopId);
            orderHistoryModel1.setType(CommonConstants.HISTORY_REPORT);
            orderHistoryModel1.setUserRequirement(shopModel.getName());
            orderHistoryModel1.setResult(shopModel.getShopReport());
            orderHistoryModel1.setUserId(userId);
            orderHistoryModel1.setShareId(shareId);
            orderHistoryModel1.setDeleted(0);
            orderHistoryModelMapper.insertSelective(orderHistoryModel1);
            shopDetailsResult.setShareId(orderHistoryModel1.getShareId());
        } else {
            orderHistoryModel1.setId(orderHistoryModel.getId());
            orderHistoryModel1.setUpdated(l);
            orderHistoryModel1.setResult(shopModel.getShopReport());
            orderHistoryModelMapper.updateByPrimaryKeySelective(orderHistoryModel1);
            shopDetailsResult.setShareId(orderHistoryModel.getShareId());
        }
        return shopDetailsResult;
    }
}
